import React, { useContext, useMemo, useRef, useState } from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { prefix } from '../../../config';
import { useSelections } from '../../../hooks';
import { deepClone, getOption, isNullOrUndefined } from '../../../utils';
import {
  CHECKBOX_SELECT_TYPE,
  defaultColumnConfig,
  defaultRowKey,
  TABLE_INDEX,
  TABLE_SELECT_CELL,
} from '../../config';
import '../../style/EditableTable.less';
import { SvgSetting } from '../../Svg';
import * as utils from '../../utils';
import BaseTable from '../BaseTable';
import TableContext from '../TableContext';
import { SelectCheckbox, SelectRadio, SettingModal } from './index';

import type {
  CellContext,
  ColumnOrderState,
  TableOptions,
  TableState,
} from '@tanstack/react-table';
import type { Options } from '../../../type';
import type { Context } from '../../context/table';
import type {
  AnyObject,
  Column,
  ColumnMeta,
  DisplayTableProps as Props,
  RowSelection,
  TableContextRef,
} from '../../type';
import type { ConfirmData, SettingCheckBoxInfo } from './SettingModal';

function DisplayTable<T extends AnyObject>(
  props: Props<T>,
  ref: React.ForwardedRef<TableContextRef<T>>,
) {
  const { isShowIndex, isCanSetting, dragSrotType, ...defaultTableProps } =
    props;
  const {
    prefixCls = prefix.editableTable,
    context,
    dataSource = [],
    rowKey = defaultRowKey,
  } = defaultTableProps;
  const {
    size = 'large',
    isFixedHeight,
    bordered = true,
    pagination = false,
  } = defaultTableProps;
  const {
    id,
    isCanResizeColumn,
    isShowSummary,
    tableStyle,
    tableBoxStyle,
    defaultStatus,
  } = defaultTableProps;
  const { table: tableContextInfo } = useContext<Context<T>>(context);
  const baseTableRef = useRef<TableContextRef<T>>(null);
  const tableId = useMemo(() => id || utils.createTableId('table'), [id]);
  const rowSelection = useMemo(
    () => utils.createRowSelection(rowKey, props.rowSelection),
    [rowKey, props.rowSelection],
  );
  const selectionDataSource = useMemo(
    () => utils.setSelectionDataSource(dataSource, rowSelection),
    [dataSource, rowSelection],
  );
  const [
    selectedRows,
    { selectStatus, getIsSelected, toggle, toggleAll, select, unSelect },
  ] = useSelections(selectionDataSource, {
    rowKey,
    selectType: rowSelection?.type,
  });

  /** 列选择 */
  const setColumnSelect = (
    columns: Column<T>[],
    rowSelection: RowSelection<T>,
  ) => {
    const { width, ...defaultConfig } = defaultColumnConfig[TABLE_SELECT_CELL];
    const {
      type: selectType,
      isCanRepeatSelection,
      columnWidth,
    } = rowSelection;
    const isCheckboxSelectType = selectType === CHECKBOX_SELECT_TYPE;
    const SelectHeader = () => {
      const disabled = !isCanRepeatSelection && !selectionDataSource.length;
      const checked = selectStatus === 'all' || !selectionDataSource.length;
      const indeterminate = selectStatus === 'partially';
      const onChange = () => rowSelection.onChange?.(toggleAll());
      const props = { disabled, checked, indeterminate, onChange };
      return isCheckboxSelectType ? (
        <div className={`${prefixCls}-setting`}>
          <SelectCheckbox {...props} />
        </div>
      ) : null;
    };
    const SelectCell = (info: CellContext<T, unknown>) => {
      const { row } = info;
      const { original: data, index } = row;
      const props =
        rowSelection && rowSelection.selectCellProps
          ? rowSelection.selectCellProps(data, index)
          : {};
      const Component = isCheckboxSelectType ? SelectCheckbox : SelectRadio;
      const checked = isCheckboxSelectType
        ? getIsSelected(data, rowSelection?.selectedRows) || getIsSelected(data)
        : getIsSelected(data);
      const onChange = () => rowSelection.onChange?.(toggle(data));
      return (
        <Component
          disabled={props.disabled}
          checked={checked}
          onChange={onChange}
        />
      );
    };
    return [
      {
        id: TABLE_SELECT_CELL,
        size: columnWidth || width,
        meta: defaultConfig,
        header: SelectHeader,
        cell: SelectCell,
      },
      ...columns,
    ];
  };
  /** 列索引 */
  const setColumnIndex = (
    columns: Column<T>[],
    {
      isShowIndex,
      isCanSetting,
    }: { isShowIndex?: boolean; isCanSetting?: boolean },
  ) => {
    const { width, ...defaultConfig } = defaultColumnConfig[TABLE_INDEX];
    const tableColumns: Column<T>[] = deepClone(columns);

    if (!!columns.length && (isShowIndex || isCanSetting)) {
      const Setting = (
        <div className={`${prefixCls}-setting`}>
          <SvgSetting
            width={20}
            height={20}
            onClick={() => setIsShowSettingModal(!isShowSettingModal)}
          />
        </div>
      );
      const header = () => (isCanSetting ? Setting : '序号');
      const cell = (info: CellContext<T, unknown>) =>
        isShowIndex || (isCanSetting && isNullOrUndefined(isShowIndex))
          ? info.row.index + 1
          : '';
      tableColumns.unshift({
        id: TABLE_INDEX,
        size: width,
        meta: defaultConfig,
        header,
        cell,
      });
    }
    return tableColumns;
  };

  const columns = useMemo(
    () => utils.initColumns(props.columns),
    [props.columns],
  );
  /** 平铺columns */
  const baseColumns = useMemo(() => {
    const flattedColumn = utils.getAllFlatColumns(columns);
    const indexColumns = setColumnIndex(flattedColumn, {
      isShowIndex,
      isCanSetting,
    });
    console.log(flattedColumn, indexColumns);

    return rowSelection
      ? setColumnSelect(indexColumns, rowSelection)
      : indexColumns;
  }, [
    columns,
    isShowIndex,
    isCanSetting,
    rowSelection,
    selectedRows,
    selectStatus,
    selectionDataSource,
  ]);

  const [isShowSettingModal, setIsShowSettingModal] = useState(false);
  const [columnOrder, setColumnOrder] = useState<ColumnOrderState>(
    utils.initColumnOrder(baseColumns),
  ); // 列顺序
  const [columnVisibility, setColumnVisibility] = useState<SettingCheckBoxInfo>(
    utils.initColumnVisibility(baseColumns),
  );
  /** 列显示隐藏 */
  const [columnSummary, setColumnSummary] = useState(
    utils.initColumnSummary(baseColumns, columnVisibility),
  ); // 列合计
  const dragTypes = useMemo(
    () => utils.getDragTypes(dragSrotType),
    [dragSrotType],
  ); // 拖拽配置
  const columnPinning = useMemo(
    () => utils.getColumnPinning(baseColumns),
    [baseColumns],
  ); // 列固定

  const tableData: T[] = useMemo(() => {
    const columnFormulaInfo = utils.getColumnFormulaInfo(baseColumns);
    const calculatedDataSource = utils.calculateTableFormula(
      dataSource,
      columnFormulaInfo,
    ); // 计算列公式
    return utils.handleRowKey(calculatedDataSource, pagination, rowKey, true);
  }, [rowKey, dataSource, baseColumns, pagination]);
  /** 表格自定义state */
  const tableState = useMemo(() => {
    const state: Partial<TableState> = { columnPinning, columnVisibility };
    if (dragTypes.includes('column')) state.columnOrder = columnOrder; // 列顺序
    return state;
  }, [
    isShowIndex,
    isCanSetting,
    dragTypes,
    columnOrder,
    columnVisibility,
    columnPinning,
  ]);
  /** 表格选项 */
  const deps = [
    isCanResizeColumn,
    isCanSetting,
    isShowIndex,
    tableState,
    dragTypes,
  ];
  const tableOptions = useMemo(() => {
    const defaultColumn: Partial<Column<T>> = {
      cell: (info) => {
        const { original: data, index } = info.row;
        const columnMeta = (info.column.columnDef.meta as ColumnMeta<T>) || {};
        const { dataKey, editType } = columnMeta;
        const value = dataKey ? data[dataKey] : info.getValue();
        if (isNullOrUndefined(value)) return '';
        // 处理展示表格下拉列的值的展示
        if (editType === 'select') {
          const { editProps, editPropsFn } = columnMeta;
          const options: Options =
            editPropsFn?.(data, index)?.options || editProps?.options || [];
          return getOption(value, options).label || value;
        } else {
          return value;
        }
      },
    };
    const options: Partial<TableOptions<T>> = {
      state: tableState,
      defaultColumn,
    };
    // 拖拽表格选项配置
    if (dragTypes.includes('column'))
      options.onColumnOrderChange = setColumnOrder;
    if (dragTypes.includes('row')) options.getRowId = (row) => row.id;
    if (isCanResizeColumn) options.columnResizeMode = 'onChange'; // 调整列宽表格选项配置
    if (isShowIndex && isCanSetting)
      options.onColumnVisibilityChange = setColumnVisibility; // 列显示表格选项配置
    // props传入的表格选项配置
    if (props.tableOptions) {
      const { state, ...tableOptions } = props.tableOptions;
      Object.assign(options, tableOptions, {
        state: { ...tableState, ...state },
      });
    }
    return options;
  }, [...deps, props.tableOptions, tableContextInfo.isCanEdit]);

  const onConfirmSettingModal = (data: ConfirmData) => {
    const { columnVisibility, columnSummary } = data;
    setColumnVisibility(columnVisibility);
    setColumnSummary(columnSummary);
    setIsShowSettingModal(false);
  };

  const baseProps = {
    size,
    prefixCls,
    rowKey,
    bordered,
    isCanResizeColumn,
    isShowSummary,
    isFixedHeight,
    tableOptions,
  };
  const tableProps = {
    tableStyle,
    tableBoxStyle,
    defaultStatus,
    columnPinning,
    columnSummary,
    columnVisibility,
  };
  const restProps = {
    dragTypes,
    id: tableId,
    columns: baseColumns,
    dataSource: tableData,
    pagination,
  };
  const tableFnProps = { onRow: props.onRow, onCell: props.onCell };
  const baseTableProps = {
    ...baseProps,
    ...tableProps,
    ...restProps,
    ...tableFnProps,
  };
  // 选择表格
  if (rowSelection) {
    Object.assign(baseTableProps, {
      tableBoxStyle: {
        display: 'flex',
        flexDirection: 'column',
        flex: 1,
        height: 'unset',
      },
      tableStyle: { flex: 1 },
      onRow: (data) => ({
        onClick: () => {
          const { isCanRepeatSelection, selectedRows: preSelectedRows = [] } =
            rowSelection;
          if (
            isCanRepeatSelection ||
            !preSelectedRows.map((item) => item[rowKey]).includes(data[rowKey])
          ) {
            rowSelection.onChange?.(toggle(data));
          }
        },
        ...props.onRow,
      }),
    });
  }
  const settingModalProps = {
    columnVisibility,
    columnSummary,
    visible: isShowSettingModal,
    isShowSummary,
  };
  React.useImperativeHandle(ref, () => ({
    getTableContext: baseTableRef.current.getTableContext,
    onResizeTable: baseTableRef.current.onResizeTable,
    getSelectedRows: () => selectedRows,
    selectRow: select,
    unSelectRow: unSelect,
  }));

  return (
    <>
      <BaseTable
        {...baseTableProps}
        ref={baseTableRef}
        context={context}
        onChangeDataSource={props.onChangeDataSource}
        onChangePagination={props.onChangePagination}
      ></BaseTable>
      {isCanSetting && (
        <SettingModal
          {...settingModalProps}
          columns={utils.adjustColumnOrder(columns, columnPinning)}
          onConfirm={onConfirmSettingModal}
          onCancel={() => setIsShowSettingModal(false)}
        />
      )}
    </>
  );
}

function DisplayTableDnd<T extends AnyObject>(
  props: Props<T>,
  ref: React.ForwardedRef<TableContextRef<T>>,
) {
  return (
    <DndProvider backend={HTML5Backend}>
      <TableContext {...props} Table={DisplayTable} ref={ref} />
    </DndProvider>
  );
}
export default React.forwardRef(DisplayTableDnd) as <T>(
  props: Props<T> & { ref?: React.ForwardedRef<TableContextRef<T>> },
) => ReturnType<typeof DisplayTableDnd>;
